package cooperate

import (
	"context"
	"errors"
	"fmt"
	"math/rand"
	"strings"
	"sync"
	"time"

	"gddgame.cc/galaxy/common/feature/orbit"
	"gddgame.cc/galaxy/common/feature/orbit/chess_protocol"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/common/service/pathfinding"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/cache"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/serialize"
)

const (
	StatKeyPrefix = "stat_"
)

var (
	ValidTypeError = errors.New("type is error, not register")
	DateInt        = &DateInstance{StartUpTime: time.Now().UnixNano() / 1e6}
	Timer          = NewTimerTransform()
	Stat           = NewStatTransform()
)

type OnUpdateNoticeInf interface {
	OnUpdate(notice *UpdateNotice)
	OnQueue(queue *Queue)
	OnNotice(notice *Notice)
	//OnError(error *ErrorNotice)
}

type OnLocationInf interface {
	Distance(start []byte, end []byte) int
	MinDistance(positions [][]byte, target []byte) int
	SmallAngle(start []byte, end []byte) [][]byte
	GetDirection(start []byte, end []byte) []byte
	UpdateLocation(position []byte, lastLocation string) (string, bool)
	//CanPath(identity int, t byte, identityMask int, selfMask int, otherMask int) bool
	Equal(start []byte, end []byte) bool
	TriangleDistance(position []byte, distance int) [][]byte
	RangeDistance(position []byte, distance int) [][]byte
	SquareDistance(position []byte, width int, height int) [][]byte
	RingDistance(position []byte, distance int) [][]byte
}

type OnPathInf interface {
	Location(position []byte) string
	Block() orbit.Location
	OnPathFinding(start []byte, end []byte, mask serialize.AutoIStruct, complete bool) [][]byte
	OnPlanFinding(start []byte, end []byte, mask serialize.AutoIStruct, complete bool) ([][]byte, [][]byte)
	OnAutoFinding(start []byte, end []byte, timestamp int64, request serialize.AutoIStruct) [][]byte

	UpdateNode(position []byte, identity int, t byte)
	UpdateFixed(positions [][]byte, identity int, t byte, view byte, item []byte, timestamp int64)
	MoveSeat(item []byte, start []byte, end []byte, startTime int64, identity int, view byte, extend serialize.AutoIStruct) bool
	GetNode(positions []byte) (int, byte, []byte)
	GetItemList(positions [][]byte, timestamp int64) ([]byte, [][]byte, []int)
	GetFixedList(positions [][]byte) ([][]byte, []int)
	GetItem(position []byte, timestamp int64) (byte, []byte, int)
	CanAndPreMove(start []byte, end []byte, timestamp int64, request serialize.AutoIStruct) []byte
	GetLinks(position []byte) pathfinding.RelationLinkManagerSlice
	GetLinksBy(relation byte, position []byte) [][]byte
	AddLinks(item []byte, relation byte, positions [][]byte) bool
	RemoveLinks(item []byte, relation byte, positions [][]byte) bool
	HasView(start []byte, target []byte, identity int, distance int, timestamp int64) bool
	HasViewOther(start []byte, target []byte, identity int, distance int, timestamp int64) bool
	CanAndPreRange(position []byte, distance int, timestamp int64, request []serialize.AutoIStruct) [][]byte
	RandomPosition(canType int, canFix bool, canSeat bool, timestamp int64) []byte
	ServiceExecute(event interface{}, params []interface{}) interface{}
}

type ScheduleOperator interface {
	AddRepeatSchedule(mapNoId string, content *ScheduleContent, event structure.EventData, repeat int, endTime int) error
	AddTouchSchedule(mapNoId string, content *ScheduleContent, times int, position []byte, t LogicType, logicInfo serialize.IStruct, params structure.ParamSlice) error
	AddOnceSchedule(mapNoId string, content *ScheduleContent, event structure.EventData, params structure.ParamSlice) error
}

type EventOperator interface {
	MakeQuery(accountId int, identity int, event byte, params []interface{}, checks [][]CheckData) structure.EventData
	MakeOperateEvent(operates []OperateData, checks [][]CheckData) structure.EventData
}

type LogicOperate interface {
	def.Context
	EventOperator
	ScheduleOperator
	ScheduleTime() int64
	TaskTime() int64
	IncrTypeId(mapNoId string, t structure.PublicDataType) int
	GetDetailCache(mapInstance MapBase, data structure.Data) PropsInstance
	UpdateDetailCache(current bool, mapInstance MapProxy, data structure.Data, update *UpdateContent) (PropsInstance, *chess_protocol.UpdatePublicData, bool)
	GetList(mapNoId string, data structure.Data, depend *BeDependDefine) []interface{}
	PushSchedule(schedule *ScheduleBuilder)
	PushTask(task *TaskBuilder)
	PushOperate(content OperateContent, targetTime int64)
	Mode(mapInstance MapProxy, from structure.Data, target structure.Data, eventProp structure.EventData, targetTime int64, extend *ModeExtend) bool
	ScheduleBuilder() *ScheduleBuilder
	TaskBuilder() *TaskBuilder
	OperateBuilder() *OperateBuilder
	EventBuilder() *EventBuilder
	PushNotice(mapNoId string, accountId int, event byte, content []byte)
	ClearEvent(mapNoId string, data structure.Data, event byte)
	GetEventsCache(mapInstance MapProxy, data structure.Data, events []byte) []*structure.EventData
	GetEventCache(mapInstance MapProxy, data structure.Data, event byte) *structure.EventData
	GetPropsCache(mapInstance MapProxy, data structure.Data, props []string) map[string]interface{}
	ListDepend(mapInstance MapProxy, t structure.PublicDataType, id interface{}, key string) []PropsInstance

	TransformMap(allMap map[string][]interface{}, ps string, item interface{})
	SyncToOrbit(mapInstance MapProxy, allMap map[string][]interface{}, t int64)
}

type MapDefined interface {
	def.Context
	DataDefined
	OnLocationInf
	GetMap(mapNoId string) *MapInstance
}

type MapCenter interface {
	MapDefined
	LogicOperate
}

type MapBase interface {
	MapCenter
	OnPathInf

	GetMapNoId() string
	GetMapTarget() *structure.BaseData
	GetMapData() *MapData
	GetMode() chess_protocol.ChessMode
}

type MapProxy interface {
	MapBase
	TypeDefined
}

type MapDelegate interface {
	OnQuery(accountId int, identity int, event byte, params []interface{}) interface{}
}

type MapContentProxy struct {
	MapContent
	context.Context
	context.CancelFunc
}

type MapContent interface {
	OnStart(master bool, proxy MapProxy, context context.Context, data PropsInstance) error
	OnStop()
	// 自定义定时器
	Execute(task string)
}

type TypeContentProvider interface {
	GetMapContent(mapNoId string, content string) MapContent
}

type TypeDefined interface {
	BindMapBase(proxy MapBase)
	ParseMap(data []byte)
	TransformLoad(t structure.PublicDataType, instance PropsInstance, message *chess_protocol.Message) (string, interface{})
	OnPreLoadMap()
	OnInitMap()
	OnUpdateMap()
	OnStartMap()
	OnQuery(accountId int, identity int, event byte, params []interface{}) interface{}
	OnEvent(event byte, params []interface{})
	OnError(accountId int, err error)
	Move(info *structure.ScheduleInfo, content *MoveScheduleContent)
	Touch(info *structure.ScheduleInfo, content *TouchScheduleContent)
	Custom(info *structure.ScheduleInfo, content *CustomScheduleContent)
	OnUpdateData(info PropsInstance, current bool)
	OnCreateHandle(data *CreateOperateData)
	OnCreateBefore(from PropsInstance, info PropsInstance)
	OnCreateAfter(info PropsInstance, current bool)
	OnResetBefore(from PropsInstance, info PropsInstance)
	OnResetAfter(info PropsInstance, current bool)
	OnDestroyBefore(from PropsInstance, info PropsInstance)
	OnDestroyAfter(info PropsInstance, current bool)
}

type TypeDefinedManager interface {
	Register(dm *DataManager)
	InitOperate(center MapCenter)
	DataRange(instance PropsInstance) uint16
	LoadData(mapInstance MapProxy, data structure.Data, items []BaseItem, allMap map[string][]interface{}, sync bool) ([]BaseItem, map[string][]interface{})
	GenerateAccount(accountId int, openId string, identity int) map[string]interface{}
	GetDetail(mapInstance MapBase, instance *PropInstance, extendMap map[structure.ExtendType]interface{}) PropsInstance
	UpdateProp(instance PropsInstance, update *UpdateContent)
	UpdateDetail(mapInstance MapProxy, instance PropsInstance, update *UpdateContent) *chess_protocol.UpdatePublicData
	OnOperateBefore(mapInstance MapProxy, instance PropsInstance, fd *FieldsDefine, from structure.Data, operate *UpdateOperateContent) bool
	OnOperateAfter(mapInstance MapProxy, instance PropsInstance, fd *FieldsDefine, from structure.Data, operate *UpdateOperateContent)
}

type DataDefined interface {
	structure.DateFactory
	GetKeyByDataKey(structure.PublicDataType) string
	GetDataKeyByKey(key string) structure.PublicDataType
	GetDataTypeMap() map[structure.PublicDataType]string
	IsNodeType(dataType structure.PublicDataType) bool
	NeedAdditionMapId(dataType structure.PublicDataType) bool
	NeedMapNo(dataType structure.PublicDataType) bool
	AdditionMapId(mapNoId string, dataType structure.PublicDataType, id interface{}) (string, bool)
	RemoveMapId(mapNoId string, dataType structure.PublicDataType, id interface{}) interface{}
	GetDataList() []structure.PublicDataType
	GetExtendMode(extend structure.ExtendType) structure.ExtendMode
	GetFieldsDefine(extend structure.PublicDataType) *FieldsDefine
	IsPersistence(field string) bool
	GetRandomIdentity() int
	GetRealIdentity(identityNumber int) int
	DefaultDepend(dataType structure.PublicDataType, key string) *DependDefine
	DefaultBeDepend(dataType structure.PublicDataType, key string) *BeDependDefine
	GetDefineList(public structure.PublicDataType, key string) []string
	GetDefineMap(public structure.PublicDataType, key string) map[string]int
}

type BaseItem interface {
	GetPosition() []byte
	GetIdentity() int
	GetPositions() [][]byte
	GetType() byte
	GetItem() []byte
	GetExtend() []byte
	GetView() byte
	IsSeat() bool
	IsFixed() bool
	IsNode() bool
	GetRelationLink() map[byte][][]byte
}

type TimerInstance interface {
	Prop(prefix string, id int) string
	Id(prefix string, prop string) int
	Props(prefix string, ids []int) []string
	Values(prefix string, propsInstance PropsInstance, ids []int) map[int]int64
	List(prefix string, propsInstance PropsInstance, ids []int) []int64
	Update(extendIndex byte, prefix string, ids []int, key string, value interface{}) (int, int, int64, *chess_protocol.UpdateExtend)
}

type StatInstance interface {
	Stat(statConfigs []utils.StatConfig, propsInstance PropsInstance, value int32, reset bool, needSync bool) []OperateData
	Values(execute *structure.Execute, conn structure.SafeConn, propsInstance PropsInstance, statConfigs []utils.StatConfig) map[utils.CycleKey]map[string]int32
}

type UpdateInstance interface {
	ChessProp(data *chess_protocol.Data)
	UpdateField(key string, value interface{}, content *chess_protocol.UpdatePublicData) (interface{}, bool)
	UpdateExtend(extend structure.ExtendType, total *chess_protocol.UpdateExtendTotal, content *chess_protocol.UpdatePublicData) (interface{}, bool)
}

type AbilityProxy interface {
	GetAttr(id int) (value int, time int)
	GetAttrWithKey(key string) int
	GetAttrWithId(id int) int
	GetAttrAddition(origin int, addition int) int
}

type TimeSortedContainer interface {
	LastestTime() int
}

type PropsInstance interface {
	structure.Data
	DataDefined
	Data() *structure.BaseData
	ChangeInherit(depend *DependDefine, fd *FieldsDefine, force bool)
	Inherits() map[string]*structure.BaseData
	Inherit(key string) *structure.BaseData
	GetProps(props []string) map[string]interface{}
	GetProp(prop string) interface{}
	GetProp2(prop string) (interface{}, bool)
	Timer() TimerInstance
	Stat() StatInstance
	ListDepend(t *BeDependDefine) []interface{}
	ListId(t *BeDependDefine) []string
	SetListId(t *BeDependDefine, list []string)
	ListNo(t *BeDependDefine) []int
	SetListNo(t *BeDependDefine, list []int)
	ListNode(t *BeDependDefine) []MapNode
	SetListNode(t *BeDependDefine, list []MapNode)

	Manager(force bool) (*structure.BaseData, *structure.BaseData)
	SetManager(data *structure.BaseData, force bool)

	Receive(k PropType) UpdateInstance
	BindAbility(abilityProxy AbilityProxy)
	MergeProp(key string, value interface{})
	MergeProps(info map[string]interface{})

	GetEvent(event byte) *structure.EventData
	GetEvents(events []byte) []*structure.EventData
	MergeEvents(events []structure.EventData)

	Attr(id int) (value int, time int)
	AttrWithKey(key string) int
	AttrWithId(id int) int
	AttrAddition(origin int, addition int) int

	GetFrom() *structure.BaseData
	GetTarget() *structure.BaseData
	GetTime() int64
	GetMapNoId() string

	ClearTimeSorted(logic MapCenter, extend structure.ExtendType, container TimeSortedContainer, lastTime int, interval int)

	Lock()
	Unlock()

	ToInt(prop string) int
	ToString(prop string) string
	ToInt64(prop string) int64
	ToByte(prop string) byte
	ToBytes(prop string) []byte
	ToBool(prop string) bool
	ToBytesSlice(prop string) [][]byte
	ToUint16(prop string) uint16
}

type PropInstance struct {
	*structure.BaseData
	DataDefined
	MapNoId string

	manager    *structure.BaseData
	oldManager *structure.BaseData

	proxy    AbilityProxy
	info     map[string]interface{}
	inherits map[string]*structure.BaseData

	mutex sync.RWMutex
	lock  bool
}

func NewPropInstance(df DataDefined, fd *FieldsDefine, data structure.Data, info map[string]interface{}) *PropInstance {
	mapNoId := utils.ToString(info[MapNoId])
	instance := &PropInstance{BaseData: structure.NewBaseDataFrom(data), DataDefined: df, MapNoId: mapNoId, info: info, mutex: sync.RWMutex{}}
	instance.inherits = map[string]*structure.BaseData{}
	if info == nil {
		instance.info = map[string]interface{}{}
	} else if len(info) > 0 {
		if fd != nil {
			l := fd.DependMap
			for _, depend := range l {
				//key := fd.GetDataKey(dataType)
				instance.ChangeInherit(depend, fd, true)
			}
		}
	}
	if fd != nil && fd.IsManage {
		instance.SetManager(instance.Data(), true)
	}
	return instance
}

func (instance *PropInstance) ChangeInherit(depend *DependDefine, fd *FieldsDefine, force bool) {
	//fmt.Println("change", instance.Data(), depend, fd, force)
	if depend == nil {
		return
	}
	if !instance.lock {
		instance.mutex.Lock()
	}
	id := instance.info[depend.Key]

	if id != nil {
		id = fd.RemoveMapId(instance.MapNoId, depend.Be.BeDependType, id)
		if depend.IsPosition {
			id = utils.ToBytes(id)
		} else if depend.Be.BeDependIsNo {
			id = utils.ToInt(id)
		} else if depend.Be.BeDependIsId {
			id = utils.ToString(id)
		}
		instance.inherits[depend.Key] = structure.NewBaseData(depend.Be.BeDependType, id)
		if depend.IsManage {
			instance.SetManager(instance.inherits[depend.Key], force)
		}
	} else {
		instance.inherits[depend.Key] = nil
		if depend.IsManage && !force {
			instance.SetManager(nil, force)
		}
	}
	if !instance.lock {
		instance.mutex.Unlock()
	}
}

func (instance *PropInstance) Data() *structure.BaseData {
	return structure.NewBaseDataFrom(instance)
}

func (instance *PropInstance) Inherits() map[string]*structure.BaseData {
	return instance.inherits
}

func (instance *PropInstance) Inherit(key string) *structure.BaseData {
	return instance.inherits[key]
}

func (instance *PropInstance) Timer() TimerInstance {
	return Timer
}

func (instance *PropInstance) Stat() StatInstance {
	return Stat
}

func (instance *PropInstance) BindAbility(abilityProxy AbilityProxy) {
	instance.proxy = abilityProxy
}

func (instance *PropInstance) Attr(id int) (value int, time int) {
	if instance.proxy != nil {
		return instance.proxy.GetAttr(id)
	}
	return
}
func (instance *PropInstance) AttrWithKey(key string) int {
	if instance.proxy != nil {
		return instance.proxy.GetAttrWithKey(key)
	}
	return 0
}
func (instance *PropInstance) AttrWithId(id int) int {
	if instance.proxy != nil {
		return instance.proxy.GetAttrWithId(id)
	}
	return 0
}
func (instance *PropInstance) AttrAddition(origin int, addition int) int {
	if instance.proxy != nil {
		return instance.proxy.GetAttrAddition(origin, addition)
	}
	return 0
}

func (instance *PropInstance) Manager(force bool) (*structure.BaseData, *structure.BaseData) {
	t1 := instance.manager
	t2 := instance.oldManager
	if force {
		instance.oldManager = instance.manager
	}
	return t1, t2
}

func (instance *PropInstance) SetManager(data *structure.BaseData, force bool) {
	//fmt.Println("manage", instance.Data(), data)
	instance.oldManager = instance.manager
	instance.manager = structure.NewBaseDataFrom(data)
	if force {
		instance.oldManager = instance.manager
	}
}

func (instance *PropInstance) ListDepend(t *BeDependDefine) []interface{} {
	if t.DependIsNo {
		ll := instance.ListNo(t)
		if ll == nil {
			return nil
		}
		l := make([]interface{}, len(ll))
		for index, ls := range ll {
			l[index] = ls
		}
		return l
	} else if t.DependIsId {
		ll := instance.ListId(t)
		if ll == nil {
			return nil
		}
		l := make([]interface{}, len(ll))
		for index, ls := range ll {
			l[index] = ls
		}
		return l
	} else if t.DependIsPosition {
		ll := instance.ListNode(t)
		if ll == nil {
			return nil
		}
		l := make([]interface{}, len(ll))
		for index, ls := range ll {
			l[index] = ls
		}
		return l
	}
	return nil
}

func (instance *PropInstance) ListId(t *BeDependDefine) []string {
	return nil
}

func (instance *PropInstance) SetListId(t *BeDependDefine, list []string) {

}

func (instance *PropInstance) ListNo(t *BeDependDefine) []int {
	return nil
}

func (instance *PropInstance) SetListNo(t *BeDependDefine, list []int) {

}

func (instance *PropInstance) ListNode(t *BeDependDefine) []MapNode {
	return nil
}

func (instanc *PropInstance) SetListNode(t *BeDependDefine, list []MapNode) {

}

func (instance *PropInstance) GetProps(props []string) map[string]interface{} {
	info := make(map[string]interface{}, len(props))
	instance.mutex.RLock()
	for _, key := range props {
		info[key] = instance.info[key]
	}
	instance.mutex.RUnlock()
	return info
}

func (instance *PropInstance) GetProp(prop string) interface{} {
	instance.mutex.RLock()
	v := instance.info[prop]
	instance.mutex.RUnlock()
	return v
}
func (instance *PropInstance) GetProp2(prop string) (interface{}, bool) {
	instance.mutex.RLock()
	v, ok := instance.info[prop]
	instance.mutex.RUnlock()
	return v, ok
}

func (instance *PropInstance) Lock() {
	instance.mutex.Lock()
	instance.lock = true
}

func (instance *PropInstance) Unlock() {
	instance.lock = false
	instance.mutex.Unlock()
}

func (instance *PropInstance) MergeProp(key string, value interface{}) {
	if !instance.lock {
		instance.mutex.Lock()
	}
	if value == nil {
		delete(instance.info, key)
	} else {
		instance.info[key] = value
	}
	if !instance.lock {
		instance.mutex.Unlock()
	}
	switch key {
	case MapNoId:
		instance.MapNoId = utils.ToString(value)
	}
}

func (instance *PropInstance) MergeProps(info map[string]interface{}) {
	instance.mutex.Lock()
	for key, value := range info {
		if value == nil {
			delete(instance.info, key)
		} else {
			instance.info[key] = value
		}
		switch key {
		case MapNoId:
			instance.MapNoId = utils.ToString(value)
		}
	}
	instance.mutex.Unlock()
}

func (instance *PropInstance) GetEvent(event byte) *structure.EventData {
	key := structure.GetEventKey(event)
	data, ok := instance.GetProp2(key)
	if !ok {
		return nil
	}
	return structure.GetEventData(utils.ToBytes(data))
}

func (instance *PropInstance) GetEvents(events []byte) []*structure.EventData {
	props := make([]string, len(events))
	for i, event := range events {
		props[i] = structure.GetEventKey(event)
	}
	es := make([]*structure.EventData, len(events))
	vs := instance.GetProps(props)
	for i, prop := range props {
		v := vs[prop]
		es[i] = structure.GetEventData(utils.ToBytes(v))
	}
	return es
}

func (instance *PropInstance) MergeEvents(events []structure.EventData) {
	instance.mutex.Lock()
	for _, event := range events {
		//fmt.Println("merge", event)
		key := structure.GetEventKey(event.Event)
		if event.Content == nil {
			// 删除event
			delete(instance.info, key)
		} else {
			// 更新event
			data := structure.GenerateEventData(&event, nil)
			instance.info[key] = data
		}
	}
	instance.mutex.Unlock()
}

func (instance *PropInstance) Receive(k PropType) UpdateInstance {
	return nil
}

func (instance *PropInstance) GetFrom() *structure.BaseData {
	return instance.Data()
}
func (instance *PropInstance) GetTarget() *structure.BaseData {
	return instance.Data()
}
func (instance *PropInstance) GetTime() int64 {
	return 0
}
func (instance *PropInstance) GetMapNoId() string {
	return instance.MapNoId
}

func (instance *PropInstance) ClearTimeSorted(logic MapCenter, extend structure.ExtendType, container TimeSortedContainer, lastTime int, interval int) {
	tt := container.LastestTime()
	current := logic.CurrentSecond()
	if tt < current && tt-lastTime > interval {
		builder := logic.OperateBuilder()
		builder.BindMapNoId(instance.MapNoId).Target(*instance.Data())
		builder.Update(*instance.Data(), nil).ClearTimeSorted(extend, current).Operate(0, nil)
	}
}

func (instance *PropInstance) ToInt(prop string) int {
	return utils.ToInt(instance.GetProp(prop))
}

func (instance *PropInstance) ToString(prop string) string {
	return utils.ToString(instance.GetProp(prop))
}

func (instance *PropInstance) ToByte(prop string) byte {
	return utils.ToByte(instance.GetProp(prop))
}

func (instance *PropInstance) ToInt64(prop string) int64 {
	return utils.ToInt64(instance.GetProp(prop))
}

func (instance *PropInstance) ToBytes(prop string) []byte {
	return utils.ToBytes(instance.GetProp(prop))
}

func (instance *PropInstance) ToBool(prop string) bool {
	return utils.ToBool(instance.GetProp(prop))
}

func (instance *PropInstance) ToBytesSlice(prop string) [][]byte {
	return utils.ToBytesSlice(instance.GetProp(prop))
}

func (instance *PropInstance) ToUint16(prop string) uint16 {
	return utils.ToUint16(instance.GetProp(prop))
}

type TimerTransform struct {
}

func NewTimerTransform() *TimerTransform {
	instance := &TimerTransform{}
	return instance
}

func (instance *TimerTransform) Prop(prefix string, id int) string {
	return prefix + utils.ToString(id)
}

func (instance *TimerTransform) Id(prefix string, prop string) int {
	return utils.ToInt(strings.TrimPrefix(prop, prefix))
}

func (instance *TimerTransform) Value(prefix string, value interface{}) int64 {
	return utils.ToInt64(value)
}

func (instance *TimerTransform) Props(prefix string, ids []int) []string {
	props := make([]string, len(ids))
	for index, id := range ids {
		props[index] = prefix + utils.ToString(id)
	}
	return props
}

func (instance *TimerTransform) Values(prefix string, propsInstance PropsInstance, ids []int) map[int]int64 {
	values := make(map[int]int64, len(ids))
	props := propsInstance.GetProps(instance.Props(prefix, ids))
	for k, v := range props {
		id := utils.ToInt(strings.TrimPrefix(k, prefix))
		values[id] = utils.ToInt64(v)
	}
	return values
}

func (instance *TimerTransform) Update(extendIndex byte, prefix string, ids []int, key string, value interface{}) (int, int, int64, *chess_protocol.UpdateExtend) {
	// 将时间加入到extend更新
	id := utils.ToInt(strings.TrimPrefix(key, prefix))
	for index, directId := range ids {
		if id == directId {
			//instance.mutex.Lock()
			//instance.info[id] = utils.ToInt64(value)
			//instance.mutex.Unlock()
			return id, index, utils.ToInt64(value), &chess_protocol.UpdateExtend{
				Index: extendIndex,
				Value: utils.ToInt64(value),
				Key:   index,
			}
		}
	}
	return 0, 0, 0, nil
}

func (instance *TimerTransform) List(prefix string, propsInstance PropsInstance, ids []int) []int64 {
	list := make([]int64, len(ids))
	props := propsInstance.GetProps(instance.Props(prefix, ids))
	//instance.mutex.Lock()
	for index, id := range ids {
		prop := prefix + utils.ToString(id)
		v, ok := props[prop]
		if ok {
			//instance.info[id] = utils.ToInt64(v)
			list[index] = utils.ToInt64(v)
		}
	}
	//instance.mutex.Unlock()
	return list
}

type StatTransform struct {
}

func NewStatTransform() *StatTransform {
	instance := &StatTransform{}
	return instance
}
func (instance *StatTransform) Stat(statConfigs []utils.StatConfig, propsInstance PropsInstance, value int32, reset bool, needSync bool) []OperateData {
	data := []OperateData{}
	var operate UpdateOperate
	//fmt.Println("stat", value, reset, needSync)
	operates := []UpdateOperateContent{}
	for _, config := range statConfigs {
		if reset {
			operate = ChangeData
		} else {
			switch config.Stat {
			case utils.CountStat:
				operate = IncrData
				if needSync {
					operate = IncrDataSync
					//fmt.Println("stat sync", value, reset, needSync)
				}
			case utils.MaxStat:
				operate = ChangeDataGreater
				if needSync {
					operate = ChangeDataGreaterSync
				}
			case utils.MinStat:
				operate = ChangeDataLesser
				if needSync {
					operate = ChangeDataLesserSync
				}
			case utils.LastStat:
				operate = ChangeData
				if needSync {
					operate = ChangeDataSync
				}
			}
		}

		operate := UpdateOperateContent{
			Operate: operate,
			Key:     StatKeyPrefix + config.GetKey(),
			Value:   value,
		}
		operates = append(operates, operate)
	}
	data = append(data, NewOperateData(BatchUpdateOperate, &UpdateOperateData{
		Data:     *propsInstance.Data(),
		Operates: operates,
	}))
	return data
}

func (instance *StatTransform) Values(execute *structure.Execute, conn structure.SafeConn, propsInstance PropsInstance, statConfigs []utils.StatConfig) map[utils.CycleKey]map[string]int32 {
	result := map[utils.CycleKey]map[string]int32{}
	props := make([]string, len(statConfigs))
	for index, config := range statConfigs {
		props[index] = StatKeyPrefix + config.GetKey()
	}
	conn.Connect()
	value := execute.GetProps(conn, propsInstance, props)
	if value == nil {
		return result
	}
	for key, v := range value {
		key = strings.Trim(key, StatKeyPrefix)
		realKey, cycle := utils.ConfigKeyParse(key)
		mm, ok := result[cycle]
		if !ok {
			mm = map[string]int32{}
			result[cycle] = mm
		}
		mm[realKey] = utils.ToInt32(v)
	}
	return result
}

type DateInstance struct {
	StartUpTime int64
}

func (dm *DateInstance) GetStartUp() int64 {
	return dm.StartUpTime
}

func (dm *DateInstance) CurrentTime() int64 {
	return time.Now().UnixNano() / 1e6
}

func (dm *DateInstance) CurrentSecond() int {
	return int(time.Now().Unix())
}

func (dm *DateInstance) FormatTime(delay int64) int64 {
	var tt int64
	if delay < 1000000 {
		tt = delay + time.Now().UnixNano()/1e6
	} else {
		tt = delay
	}
	return tt
}

func (dm *DateInstance) FormatTimeFrom(delay int64, from int64) int64 {
	var tt int64
	if delay < 1000000 {
		tt = delay + from
	} else {
		tt = delay
	}
	return tt
}

func (dm *DateInstance) FormatSecond(delay int) int {
	var tt int
	if delay < 10000 {
		tt = delay + int(time.Now().Unix())
	} else {
		tt = delay
	}
	return tt
}

func (dm *DateInstance) FromStartUp(delay int64) int {
	return int(dm.FormatTime(delay) - dm.StartUpTime)
}

type MapInstance struct {
	OnPathInf
	TypeDefined
	*LogicExecute

	MapManager *MapManager

	Master  bool
	MapNoId string
	MapInfo *MapInfo
	MapData *MapData
	Version int
	Data    *structure.BaseData
	Content []MapContentProxy
	IsStart bool
	IsEnd   bool

	ScheduleChan chan structure.ScheduleInfo

	ctx    context.Context
	cancel context.CancelFunc
}

func (instance *MapInstance) ID() string {
	return instance.MapNoId
}

func (instance *MapInstance) MessageRange(event byte) uint16 {
	if instance.MapInfo.MessageRangeList == nil {
		return 0
	}
	return instance.MapInfo.MessageRangeList[event]
}

func (instance *MapInstance) GetMode() chess_protocol.ChessMode {
	return chess_protocol.LayerChessMode
}

func (instance *MapInstance) LoadMapData(sync bool) []BaseItem {
	allMap := map[string][]interface{}{}
	items := make([]BaseItem, 0, 100)
	items, allMap = instance.LoadData(instance, instance.Data, items, allMap, sync)
	if sync {
		instance.SyncToOrbit(instance, allMap, 0)
	}
	return items
}

func (instance *MapInstance) OnStart() context.Context {
	ctx, cancel := context.WithCancel(context.Background())
	instance.ctx = ctx
	instance.cancel = cancel
	info := instance.GetDetailCache(instance, instance.Data)
	conn := instance.execute.Transaction()
	conn.Connect()
	ok := false
	var v interface{}
	if info != nil {
		v, ok = info.GetProp2("version")
	}
	fmt.Println("on start", info, instance.Version, instance.Data, ok, v)
	if !ok || utils.ToInt(v) < instance.Version {
		if !ok {
			// 第一次，将基础数据写入
			instance.PushOperate(OperateContent{
				MapNoId:  instance.MapNoId,
				Checks:   nil,
				From:     instance.Data,
				Target:   instance.Data,
				Operates: instance.MapData.Init,
			}, 0)
			instance.OnInitMap()
		} else {
			instance.OnUpdateMap()
		}
		instance.PushOperate(OperateContent{
			MapNoId: instance.MapNoId,
			Checks:  nil,
			From:    instance.Data,
			Target:  instance.Data,
			Operates: []OperateData{
				NewOperateData(BatchUpdateOperate, &UpdateOperateData{
					Data: *instance.Data,

					Operates: []UpdateOperateContent{{
						Operate: ChangeData,
						Key:     "version",
						Value:   instance.Version,
					}},
				})},
		}, instance.CurrentTime())
	}
	if instance.MapData.Schedule != nil {
		schedule := instance.MapData.Schedule
		info := instance.execute.GenerateSchedule(instance.MapNoId, schedule.From, schedule.Target, schedule.Key, instance.FormatTime(schedule.Time), schedule.Schedule, schedule.Content, nil, schedule.Delay)
		instance.execute.PushSchedule(conn, info)
	}
	if instance.MapInfo.Content != nil {
		for _, content := range instance.MapInfo.Content {
			c := instance.MapManager.GetMapContent(instance.MapNoId, content)
			if c == nil {
				continue
			}
			data := instance.GetDetailCache(instance, structure.NewBaseData(MapContentType, content))
			// 地图自动运行逻辑
			// 内部定时器，master执行，client执行区分
			ctx, cancel := context.WithCancel(instance.ctx)
			err := c.OnStart(instance.Master, instance, ctx, data)
			if err != nil {
				continue
			}
			instance.Content = append(instance.Content, MapContentProxy{MapContent: c, Context: ctx, CancelFunc: cancel})
		}
	}
	instance.OnStartMap()
	_ = conn.Close()
	instance.IsStart = true
	instance.IsEnd = false
	return instance.ctx
}

func (instance *MapInstance) OnStop() {
	for index := range instance.Content {
		proxy := &instance.Content[index]
		proxy.OnStop()
		proxy.CancelFunc()
	}
	instance.cancel()
	instance.UpdateDetailCache(true, instance, instance.Data, &UpdateContent{Mode: DeleteUpdateMode})
	instance.IsEnd = true
	instance.IsStart = false
}

func (instance *MapInstance) GetMapNoId() string {
	return instance.MapNoId
}

func (instance *MapInstance) GetMapTarget() *structure.BaseData {
	return instance.Data
}
func (instance *MapInstance) GetMapData() *MapData {
	return instance.MapData
}

type MapLoadDelegate interface {
	OnLoadMap(instance *MapInstance)
	OnReloadMap(instance *MapInstance)
}

type MapManager struct {
	DataDefined
	OnLocationInf
	TypeContentProvider
	def.Logger
	def.Store

	memory *cache.MemoryCache

	MapLoadDelegate MapLoadDelegate
	MapMap          sync.Map

	defaultMap *MapInstance
}

func NewMapManager(logger def.Logger, dd DataDefined, location OnLocationInf) *MapManager {
	memory := cache.Memory(logger)
	mm := &MapManager{
		OnLocationInf: location,
		DataDefined:   dd,

		Logger: logger.LoggerWrap("cooperate", "mapManager"),
		Store:  memory.Store("mapManager"),

		defaultMap: &MapInstance{MapNoId: ""},
	}
	mm.defaultMap.MapManager = mm
	return mm
}

func (mm *MapManager) ID() string {
	return "mapManager"
}

func (mm *MapManager) ReloadMap(mapNoId string) *MapInstance {
	td, ok := mm.MapMap.Load(mapNoId)
	var mapInstance *MapInstance
	if ok {
		mapInstance = td.(*MapInstance)
		mm.MapLoadDelegate.OnReloadMap(mapInstance)
	} else {
		mapInstance = &MapInstance{MapNoId: mapNoId}
		mm.MapLoadDelegate.OnLoadMap(mapInstance)
		mm.MapMap.Store(mapNoId, mapInstance)
	}
	mapInstance.OnPreLoadMap()
	return mapInstance
}

func (mm *MapManager) DefaultInstance() *MapInstance {
	return mm.defaultMap
}

func (mm *MapManager) GetMap(mapNoId string) *MapInstance {
	td, ok := mm.MapMap.Load(mapNoId)
	var mapInstance *MapInstance
	if !ok {
		mapInstance = &MapInstance{MapNoId: mapNoId}
		mm.MapLoadDelegate.OnLoadMap(mapInstance)
		mm.MapMap.Store(mapNoId, mapInstance)
		mapInstance.OnPreLoadMap()
	} else {
		mapInstance = td.(*MapInstance)
	}
	return mapInstance
}

func (mm *MapManager) InitMap(instance *MapInstance, mapNoId string, td TypeDefined, info *MapInfo, version int) {
	instance.MapManager = mm
	instance.Data = structure.NewBaseData(structure.MapType, mapNoId)
	d := &MapData{}
	if _, err := d.UnmarshalMsg(info.Data); err != nil {
		fmt.Println("bind data", err)
	}

	d.SizeVector2 = pathfinding.DecodeVector2(d.Size)
	d.CenterVector2 = pathfinding.DecodeVector2(d.Center)

	instance.MapNoId = mapNoId
	instance.Version = version
	instance.MapInfo = info
	instance.MapData = d
	instance.TypeDefined = td
	instance.TypeDefined.ParseMap(d.Extend)
	instance.ScheduleChan = make(chan structure.ScheduleInfo, 30)

	td.BindMapBase(instance)
}

func GetData() *DataManager {
	dm := &DataManager{DateInstance: DateInt}
	return dm
}

type DataManager struct {
	*DateInstance

	DataTypeMap map[structure.PublicDataType]string
	DataKeyMap  map[string]structure.PublicDataType
	DependMap   map[structure.PublicDataType]map[string]*DependDefine
	BeDependMap map[structure.PublicDataType]map[string]*BeDependDefine

	ExtendModeMap           map[structure.ExtendType]structure.ExtendMode
	DataTypeFieldsDefineMap map[structure.PublicDataType]*FieldsDefine
	IdentityList            []int
	PersistenceMap          map[string]bool
	SyncDefineList          map[structure.PublicDataType]map[string][]string
	SyncDefineMap           map[structure.PublicDataType]map[string]map[string]int
}

func (dm *DataManager) Init() error {
	dm.DataKeyMap = make(map[string]structure.PublicDataType)

	dm.DataTypeMap = map[structure.PublicDataType]string{
		structure.ScheduleType: structure.ScheduleDataType,
		structure.TaskType:     structure.TaskDataType,
		structure.MapType:      structure.MapDataType,
		MapContentType:         MapContentDataType,
	}
	dm.DataTypeFieldsDefineMap[MapContentType] = MapContentField
	if dm.SyncDefineList == nil {
		dm.SyncDefineList = map[structure.PublicDataType]map[string][]string{}
	}
	dm.SyncDefineMap = map[structure.PublicDataType]map[string]map[string]int{}
	for dataType, keys := range dm.SyncDefineList {
		dd := map[string]map[string]int{}
		for key, ll := range keys {
			dd[key] = utils.StringArrayToMap(ll)
		}
		dm.SyncDefineMap[dataType] = dd
	}

	dm.DependMap = map[structure.PublicDataType]map[string]*DependDefine{}
	dm.BeDependMap = map[structure.PublicDataType]map[string]*BeDependDefine{}
	for _, fd := range dm.DataTypeFieldsDefineMap {
		fd.init(dm, dm.DataTypeFieldsDefineMap)
		dm.DataTypeMap[fd.DataType] = fd.DataKey
	}
	for dataType, beDataKey := range dm.DataTypeMap {
		be := map[string]*DependDefine{}
		dependFd := dm.DataTypeFieldsDefineMap[dataType]
		dependIsPosition := false
		//dependIsManage := false
		dependIsNo := false
		dependIsId := false
		if dependFd != nil {
			dependIsPosition = dependFd.IsPosition
			//dependIsManage = dependFd.IsManage
			dependIsNo = dependFd.IsNo
			dependIsId = dependFd.IsId
		}
		dm.DataKeyMap[beDataKey] = dataType
		for beDataType, dataKey := range dm.DataTypeMap {
			beDependFd := dm.DataTypeFieldsDefineMap[beDataType]
			bBe, ok := dm.BeDependMap[beDataType]
			if !ok {
				bBe = map[string]*BeDependDefine{}
				dm.BeDependMap[beDataType] = bBe
				if beDependFd != nil {
					for _, b := range beDependFd.BeDepends {
						bBe[b.Depend] = b
					}
				}
			}
			beDependIsPosition := false
			if beDependFd != nil {
				beDependIsPosition = beDependFd.IsPosition
			}
			beDependsIsNo := false
			if beDependFd != nil {
				beDependsIsNo = beDependFd.IsNo
			}
			beDependsIsId := false
			if beDependFd != nil {
				beDependsIsId = beDependFd.IsId
			}
			beDependsIsManage := false
			if beDependFd != nil {
				beDependsIsManage = beDependFd.IsManage
			}
			d := &BeDependDefine{
				Index:              -1, // 默认，不同步
				BeDepend:           beDataKey,
				BeDependType:       beDataType,
				Depend:             dataKey,
				DependType:         dataType,
				BeDependIsPosition: beDependIsPosition,
				DependIsPosition:   dependIsPosition,
				BeDependIsNo:       beDependsIsNo,
				DependIsNo:         dependIsNo,
				BeDependIsId:       beDependsIsId,
				DependIsId:         dependIsId,
				IsChess:            false,
			}
			be[dataKey] = &DependDefine{
				Key:        dataKey,
				Be:         d,
				IsPosition: beDependIsPosition,
				IsManage:   beDependsIsManage,
			}
			bBe[beDataKey] = d
		}
		if dependFd != nil {
			for _, depend := range dependFd.DependMap {
				be[depend.Key] = depend
			}
		}
		dm.DependMap[dataType] = be
	}

	return nil
}

func (dm *DataManager) DefaultDepend(dataType structure.PublicDataType, key string) *DependDefine {
	d, ok := dm.DependMap[dataType]
	if !ok {
		return nil
	}
	return d[key]
}
func (dm *DataManager) DefaultBeDepend(dataType structure.PublicDataType, key string) *BeDependDefine {
	d, ok := dm.BeDependMap[dataType]
	if !ok {
		return nil
	}
	return d[key]
}

func (dm *DataManager) GetDataKeyMap() map[string]structure.PublicDataType {
	return dm.DataKeyMap
}

func (dm *DataManager) GetDataKeyByKey(key string) structure.PublicDataType {
	return dm.DataKeyMap[key]
}

func (dm *DataManager) GetKeyByDataKey(public structure.PublicDataType) string {
	return dm.DataTypeMap[public]
}

func (dm *DataManager) GetDataTypeMap() map[structure.PublicDataType]string {
	return dm.DataTypeMap
}

func (dm *DataManager) IsNodeType(dataType structure.PublicDataType) bool {
	// 传递到寻路系统
	// 批量获取地图的所有节点信息
	return dataType == NodeType || dataType == PathNodeType
}

func (dm *DataManager) NeedAdditionMapId(dataType structure.PublicDataType) bool {
	fd := dm.DataTypeFieldsDefineMap[dataType]
	if fd == nil {
		return false
	}
	return fd.IsPosition || fd.IsMap
}

func (dm *DataManager) NeedMapNo(dataType structure.PublicDataType) bool {
	// AccountType 由mysql存储map信息
	return AccountType != dataType
}

func (dm *DataManager) AdditionMapId(mapNoId string, dataType structure.PublicDataType, id interface{}) (string, bool) {
	if !dm.NeedAdditionMapId(dataType) {
		return utils.ToString(id), false
	}
	return mapNoId + "/" + utils.ToString(id), true
}

func (dm *DataManager) RemoveMapId(mapNoId string, dataType structure.PublicDataType, id interface{}) interface{} {
	if !dm.NeedAdditionMapId(dataType) {
		return id
	}
	//fmt.Println("m", id, strings.Replace(utils.ToString(id), mapNoId+"/", "", 1))
	return strings.Replace(utils.ToString(id), mapNoId+"/", "", 1)
}

func (dm *DataManager) GetDataList() []structure.PublicDataType {
	list := make([]structure.PublicDataType, 0, len(dm.DataTypeMap))
	for t, _ := range dm.DataTypeMap {
		list = append(list, t)
	}
	return list
}

func (dm *DataManager) GetExtendMode(extend structure.ExtendType) structure.ExtendMode {
	return dm.ExtendModeMap[extend]
}

func (dm *DataManager) GetFieldsDefine(public structure.PublicDataType) *FieldsDefine {
	return dm.DataTypeFieldsDefineMap[public]
}

func (m *DataManager) IsPersistence(field string) bool {
	b, o := m.PersistenceMap[field]
	return o && b
}

func (dm *DataManager) GetRandomIdentity() int {
	rand.Seed(time.Now().UnixNano())
	r := rand.Intn(len(dm.IdentityList))
	return dm.IdentityList[r]
}

func (dm *DataManager) GetRealIdentity(identityNumber int) int {
	if identityNumber > len(dm.IdentityList) {
		return 0
	}

	return dm.IdentityList[identityNumber-1]
}

func (dm *DataManager) GetDefineList(public structure.PublicDataType, key string) []string {
	if kl, ok := dm.SyncDefineList[public]; !ok {
		return nil
	} else if ll, ok := kl[key]; ok {
		return ll
	}
	return nil
}

func (dm *DataManager) GetDefineMap(public structure.PublicDataType, key string) map[string]int {
	if kl, ok := dm.SyncDefineMap[public]; !ok {
		return nil
	} else if ll, ok := kl[key]; ok {
		return ll
	}
	return nil
}

type DataTypeContainer struct {
	Mutex sync.RWMutex
	Cache map[interface{}]PropsInstance
}

func NewDataTypeContainer() *DataTypeContainer {
	dtc := &DataTypeContainer{
		Mutex: sync.RWMutex{},
		Cache: map[interface{}]PropsInstance{},
	}
	return dtc
}
